<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Spark • Raycasting</title>
  <style>
    body {
      margin: 0;
    }

    header {
      position: absolute;
      color: silver;
      font-family: sans-serif;
      padding-top: 20px;
      text-align: center;
      width: 100vw;
    }
  </style>
</head>

<body>
  <header>Click to select</header>
  <script type="importmap">
    {
      "imports": {
        "three": "/examples/js/vendor/three/build/three.module.js",
        "@sparkjsdev/spark": "/dist/spark.module.js"
      }
    }
  </script>
  <script type="module">
    import * as THREE from "three";
    import { SplatMesh, PackedSplats } from "@sparkjsdev/spark";
    import { getAssetFileURL } from "/examples/js/get-asset-url.js";

    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10);
    camera.position.set(0, -0.25, -1.5);
    camera.lookAt(0, -0.15, 0);
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    window.addEventListener('resize', onWindowResize, false);
    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    }

    // Add robots
    const NUM_ROBOTS = 5;
    const robots = [];
    const splatURL = await getAssetFileURL("robot-head.spz");
    const packedSplats = new PackedSplats({ url: splatURL });
    for (let i = 0; i < NUM_ROBOTS; i++) {
      const robot = new SplatMesh({ packedSplats });
      robot.rotation.x = Math.PI;
      robot.scale.setScalar(0.2);
      robot.position.set(0, 0, i);
      robot.speed = 600 + i * 10;
      robot.angle = 0;
      robot.clickedTimer = false;
      scene.add(robot);
      robots.push(robot);
    }

    // Raycast logic
    const raycaster = new THREE.Raycaster();
    renderer.domElement.addEventListener("click", (event) => {
      const clickCoords = new THREE.Vector2(
        (event.clientX / renderer.domElement.width) * 2 - 1,
        -(event.clientY / renderer.domElement.height) * 2 + 1,
      );

      // Run raycaster
      raycaster.setFromCamera(clickCoords, camera);
      const hits = raycaster.intersectObjects(scene.children);

      // Find first SplatMesh
      const index = hits.findIndex(hit => hit.object instanceof SplatMesh);
      if (index >= 0) {
        const robot = hits[index].object;
        if (!robot.clickedTimer) {
          // Tint object and start countdown timer to remove tint
          robot.recolor.set(1, 0.5, 0.5);
          robot.clickedTimer = 40;
        }
      }
    });

    // Main loop
    renderer.setAnimationLoop(function animate(time) {
      // Animate all robots, and check if it's time to remove tint
      for (let robot of robots) {
        // Pendulum movement
        robot.position.x = Math.cos(robot.angle) * 0.6;
        robot.position.y = Math.sin(robot.angle) * 0.6;
        robot.angle = Math.PI * 1.5 + Math.sin(time / robot.speed);

        if (robot.clickedTimer > 0) {
          robot.clickedTimer -= 1;
          if (robot.clickedTimer == 0) {
            // Clicked timer expired, remove tint
            robot.recolor.set(1, 1, 1);
          }
        }
      }
      renderer.render(scene, camera);
    });
  </script>
</body>

</html>
